#include "autoconfig.h"
#include "stm32f10x_spi.h"
#include "prj_type.h"
#include "project.h"
#include "stm32-chip-spi-tr700.h"
#include "env.h"
#include <stdio.h>
#include <TR700Driver.h>
#include <math.h>
#include "u_math.h"
// #include "printl.h"
/*
  # 4 种可能的数据包类型，由T1、T2、R1、R2组成
  - T1 主机发送的最小数据 4 Byte
  - T2 主机发送的扩展数据 0~256 Byte
  - R1 从机返回的最小数据 2 Byte
  - R2 从机返回的扩展数据 0~64 Byte

  #############################################################################
  1. 最小命令：主机发送4Byte、从机返回2Byte
  #############################################################################
  < --------- T1 -------------> <------ R1 ------->
  |  0 | 1   |   2  |     3    |   4  |      5
  |'S' |地址 | 命令 | 数据长度 | 状态 | 应答命令码


  #############################################################################
  2. 从机返回N字节扩展数据：N的数据量不超过64Byte
  #############################################################################
  < --------- T1 -------------> <------ R1 -------> <-- R2 -->
  | 0  | 1   |   2  |     3    |   4  |      5     |  N
  |'S' |地址 | 命令 | 数据长度 | 状态 | 应答命令码 | 数据


  #############################################################################
  3. 主机发送扩展数据n：数据量不超过256
  #############################################################################
  < --------- T1 -------------> <-- T2 ---> <------ R1 ------->
  | 0  | 1   |   2  |     3    | n(0~256)  |   4  |      5
  |'S' |地址 | 命令 | 数据长度 | 发送数据  | 状态 | 应答命令码

  #############################################################################
  4.主机发送扩展数据n、从机返回N字节扩展数据
  #############################################################################
  < --------- T1 -------------> <-- T2 ---> <------ R1 ------> <-- R2 -->
  | 0  | 1   |   2  |     3    | n(0~256) |   4  |      5     |  N
  |'S' |地址 | 命令 | 数据长度 | 发送数据 | 状态 | 应答命令码 | 数据

*/

extern char *spi_ptx;
extern unsigned int spi_plen;
extern unsigned int spi_newlen;

#define ACK_CMD_OFFSET (9)
#define ACK_CODE_OFFSET (4)



#define ACK_CMD(x) (*((x) + 2))
#define ACK_CODE(x) (*((x) + 12))

#define PRO_LEN(x)   (*((x) + ACK_CODE_OFFSET))

#define ACK_SUCCESS   (0xaa)
#define ACK_ERROR     (0x55)

#define DEF_ADDR      (0x10)

#define CKSUM_UNUSE_L (0x00)
#define CKSUM_UNUSE_H (0x00)





// = {0x47,0x4c,0x49,0x4e,0x4b,0x00,0x1c,0x30,0x00,0xa0,0xaa,0x00};
char reg_isalive[] = {'G', 'L', 'I', 'N', 'K',
                      0x00,  		// 总长度
                      0x00,
                      0x00, 		// 保留
                      DEF_ADDR,		// 地址
                      CMD_ALIVE,  	// 命令
                      ACK_SUCCESS,  	// 数据
                      CKSUM_UNUSE_L,  	// 校验和
                      CKSUM_UNUSE_H
                     };

static struct fpga_2016 {
	long a;
	char b;
} __attribute__((__packed__));

char reg_ls_w[] = {0x00, CMD_SETLS, 0x00};
// struct tr700_common_rx reg_ack = {0x00, CMD_SETLS};
char reg_ack[] = {0x00, 0xaa};




char reg_opm_r[] = {0, CMD_OPM_R,
                    0x13, 0x10,  		// 波长
                    OPM_R_1K,  			// 频率
                    0x01, 0x02, 0x03, 0x04,  	// dBm功率值浮点数
                    END,
                   };
struct tr700_getenv_rx reg_genv_rx = {
	0x00,
	0x00,
	{0}
};

struct tr700_setls_tx     reg_setls_tx;
struct tr700_setls_dbg_tx reg_setls_dbg_tx;




struct tr700_getenv_tx reg_genv_tx;
struct tr700_setenv_tx reg_senv_tx;

char envs[4][10] = {
	"im a",
	"im bbb",
	"im CC",
	"im ddd",
};



void on_getenv(void *ptr)
{
	char *val;
	static i = 0, k = 0;
	int len;

	val = _do_getenv(ptr);
	len = strlen(val);
	if (len >= PRE_ENV_LEN) {
		len = PRE_ENV_LEN - 1;
	}
	memcpy(reg_genv_rx.env, val, len);
	reg_genv_rx.env[len] = '\0';
	if (spi_isdebug) {
		printf("getenv env %s val %s\r\n", ptr, val);
	}
	return;
}

char spi_active_cmd = CMD_UNDEFINE;
void on_setenv(void *ptr)
{
	char *env = ptr;
	char *val;
	int i;

	for (i = 0; i < 60; i++) {
		if ('=' == env[i]) {
			env[i] = '\0';
			val = env + i + 1;
			break;
		}
	}

	printf("setenv %x env %s val %s\r\n", spi_active_cmd, env, val);
	_do_setenv(env, val);
}

void on_setls(void *ptr)
{
	struct tr700_setls_tx *input = (struct tr700_setls_tx *)ptr;
	float        dbm   = input->dbm;
	unsigned int mode  = input->mode;
	unsigned int ch    = input->ch;

	printf("ch %d freq %d dbm %4.2f\r\n",
	       ch,
	       mode,
	       dbm);
	Laser_dBm2Ctrl(dbm, &dev_ls);
	dev_ls.mode = mode;
	dev_ls.ch   = ch;
	Ctrl_LaserMode(&dev_ls);
	Ctrl_LaserChannel(&dev_ls);
	Ctrl_LaserDAC(&dev_ls);
}

void on_setls_dbg(void *ptr)
{
	struct tr700_setls_dbg_tx *input = (struct tr700_setls_dbg_tx *)ptr;
	short        dac   = input->dac;
	unsigned int mode  = input->mode;
	unsigned int ch    = input->ch;

	printf("ch %d mode %d dac %d\r\n",
	       ch,
	       mode,
	       dac);
	dev_ls.ch   = ch;
	dev_ls.mode = mode;
	dev_ls.dac  = dac;
	Ctrl_LaserMode(&dev_ls);
	Ctrl_LaserChannel(&dev_ls);
	Ctrl_LaserDAC(&dev_ls);
}

struct tr700_getopm_dbg_rx reg_getopm_dbg_rx;
struct tr700_getopm_rx reg_getopm_rx;

void fill_getopm(struct tr700_getopm *val)
{
	reg_getopm_rx.crx.status = CTX_F_SUCCESS;
	reg_getopm_rx.crx.cmd    = CMD_OPM_R;

	reg_getopm_rx.dbm  = val->dbm;
	reg_getopm_rx.mode = val->mode;
	reg_getopm_rx.wave = val->mode;
}

void fill_getopm_dbg(struct tr700_getopm_dbg *val)
{
	reg_getopm_dbg_rx.crx.status = CTX_F_SUCCESS;
	reg_getopm_dbg_rx.crx.cmd    = CMD_OPM_R_DBG;

	reg_getopm_dbg_rx.level  = val->level;
	reg_getopm_dbg_rx.adc    = val->adc;
	reg_getopm_dbg_rx.dbm    = val->dbm;
}

struct tr700_getls_dbg_rx reg_getls_dbg_rx;

void fill_getls_dbg(struct tr700_getls_dbg  *val)
{
	reg_getls_dbg_rx.crx.status = CTX_F_SUCCESS;
	reg_getls_dbg_rx.crx.cmd    = CMD_GETLS_DBG;


	reg_getls_dbg_rx.ch		= val->ch;
	reg_getls_dbg_rx.mode	= val->mode;
	reg_getls_dbg_rx.adc	= val->adc;
	reg_getls_dbg_rx.dac	= val->dac;
}


struct tr700_dbg_tx reg_dbg_tx;
void on_dbg(void *ptr)
{
	struct tr700_dbg_tx *input = (struct tr700_dbg_tx *)ptr;
	spi_isdebug = input->isdebug;
	printf("Debug %s\r\n", spi_isdebug ? "On" : "Off\r\n");
}

struct tr700_opm_set_tx reg_opm_set_tx;
void on_opm_set(void *ptr)
{
	struct tr700_opm_set_tx *input = (struct tr700_opm_set_tx *)ptr;
	printf("level %d\r\n", input->level);
	Ctrl_OPM_SW(input->level);
	jiffies += 1000;

	// 立马读取功率到寄存器，快速响应SPI请求
}


void on_saveenv(void *ptr)
{
	Flash_Save();
}

void on_nothing(void *ptr)
{

}


struct on_active_list {
	char *cmd;
	void (*on_cmd)(void *ptr);
	void *input;
};

struct on_active_list active_list[] = {
	{"CMD_UNDEFINE", 	on_nothing, 	NULL},				// 0x00
	{"CMD_ALIVE", 		on_nothing, 	NULL},				// 0x01
	{"CMD_GETENV_PRE", 	on_getenv,  	&reg_genv_tx},		// 0x02
	{"CMD_GETENV", 		on_nothing, 	NULL},				// 0x03
	{"CMD_SETENV", 		on_setenv,  	&reg_senv_tx},		// 0x04
	{"CMD_SAVEENV", 	on_saveenv, 	NULL},				// 0x05
	{"CMD_SETLS", 		on_setls,   	&reg_setls_tx},		// 0x06
	{"CMD_OPM_W", 		on_nothing, 	NULL},				// 0x07
	{"CMD_OPM_R", 		on_nothing, 	NULL},				// 0x08
	{"CMD_DBG", 		on_dbg, 		&reg_dbg_tx},		// 0x09
	{"CMD_OPM_R_DBG", 	on_nothing, 	NULL},				// 0x0A
	{"CMD_OPM_W_DBG", 	on_opm_set, 	&reg_opm_set_tx},	// 0x0b
	{"CMD_SETLS_DBG", 	on_setls_dbg,	&reg_setls_dbg_tx},	// 0x0c
	{"CMD_GETLS_DBG", 	on_nothing,		NULL},				// 0x0b
	// {"CMD_OPM_SET", 	on_opm_r, NULL},
};


int on_active()
{
	int cmd = spi_active_cmd;


	if (cmd >= sizeof(active_list) / sizeof(struct on_active_list)) {
		printf("unknow %x\r\n", cmd);
		// spi_active_cmd = CMD_UNDEFINE;
		return -1;
	}
	if (spi_isdebug) {
		printf("[%s]\r\n", active_list[cmd].cmd);
	}

	active_list[cmd].on_cmd(active_list[cmd].input);
	spi_active_cmd = CMD_UNDEFINE;
}


char isbusy()
{
	if (spi_active_cmd != CMD_UNDEFINE) {
		return CTX_F_BUSY;
	}
	return CTX_F_SUCCESS;
}
/**
 * @brief	根据接收到的数据
 * @param	rx  接收的内容
 * @param	len 接收的长度
 * @retval	null
 * @remarks
 * @see
 */
extern char spi_dates[100];
int spi_analyse(char *rx, int *len)
{
	unsigned int task_spi;
	int i = 0;

	if (*(rx + 0) != 'S') {
#if 0
		printf("error len %d next %d\r\n", *len, OFFSET_LEN(rx));
		for (i = 0; i < 20; i++) {
			printf("%x ", *(rx + i));
		}
		printf("*********\r\n", *len);
#endif
		return -2;
	}
	if (*len < OFFSET_LEN(rx) + MIN_PACK_LEN) {
		spi_newlen = OFFSET_LEN(rx);
		return -1;
	}

	switch(OFFSET_CMD(rx)) {
	case CMD_ALIVE:
		reg_ack[0] = CTX_F_SUCCESS;
		reg_ack[1] = CMD_ALIVE;
		spi_ptx  = (char *)reg_ack;
		spi_plen = sizeof(reg_ack);
		break;
	case CMD_SETLS:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_SETLS;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		} else {
			spi_active_cmd = CMD_SETLS;
			memcpy(&reg_setls_tx, PTR_TXVAL(rx), OFFSET_LEN(rx));

			reg_ack[0] = CTX_F_SUCCESS;
			reg_ack[1] = CMD_SETLS;
			spi_ptx = (char *)reg_ack;
			spi_plen = sizeof(reg_ack);
		}
		break;
	// case CMD_OPM_R:
	// 	spi_ptx = reg_opm_r;
	// 	spi_plen = sizeof(reg_opm_r);
	// 	break;
	case CMD_SETENV:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_SETENV;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		} else {
			spi_active_cmd = CMD_SETENV;
			memcpy(reg_senv_tx.env, rx + MIN_PACK_LEN, OFFSET_LEN(rx));

			reg_ack[0] = CTX_F_SUCCESS;
			reg_ack[1] = CMD_SETENV;
			spi_ptx = (char *)reg_ack;
			spi_plen = sizeof(reg_ack);
		}
		break;
	case CMD_GETENV_PRE:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_GETENV_PRE;
		} else {
			spi_active_cmd = CMD_GETENV_PRE;
			memcpy(reg_genv_tx.env, rx + MIN_PACK_LEN, OFFSET_LEN(rx));
			reg_ack[0] = CTX_F_SUCCESS;
			reg_ack[1] = CMD_GETENV_PRE;
		}
		spi_ptx = (char *)reg_ack;
		spi_plen = sizeof(reg_ack);
		break;
	case CMD_GETENV:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_GETENV;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		} else {
			reg_genv_rx.crx.status = CTX_F_SUCCESS;
			reg_genv_rx.crx.cmd = CMD_GETENV;

			spi_ptx = (char *)&reg_genv_rx;
			spi_plen = sizeof(reg_genv_rx);
		}
		break;
	case CMD_SAVEENV:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_SAVEENV;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		} else {
			spi_active_cmd = CMD_SAVEENV;
			reg_ack[0] = CTX_F_SUCCESS;
			reg_ack[1] = CMD_SAVEENV;
		}
		spi_ptx = (char *)reg_ack;
		spi_plen = sizeof(reg_ack);
		break;
	case CMD_OPM_R:
		spi_ptx = (char *)&reg_getopm_rx;
		spi_plen = sizeof(reg_getopm_rx);
		break;
	case CMD_DBG:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_DBG;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		} else {
			reg_ack[0] = CTX_F_SUCCESS;
			reg_ack[1] = CMD_DBG;
			spi_active_cmd = CMD_DBG;
			memcpy(&reg_dbg_tx, PTR_TXVAL(rx), OFFSET_LEN(rx));
		}
		spi_ptx = (char *)&reg_ack;
		spi_plen = sizeof(reg_ack);
		break;
	case CMD_OPM_W_DBG:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_OPM_W_DBG;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		} else {
			spi_active_cmd = CMD_OPM_W_DBG;
			memcpy(&reg_opm_set_tx, PTR_TXVAL(rx), OFFSET_LEN(rx));

			reg_ack[0] = CTX_F_SUCCESS;
			reg_ack[1] = CMD_OPM_W_DBG;
			// on_active();
		}
		spi_ptx = (char *)&reg_ack;
		spi_plen = sizeof(reg_ack);
		break;
	case CMD_OPM_R_DBG:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_OPM_R_DBG;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		} else {
			spi_active_cmd = CMD_OPM_R_DBG;
			spi_ptx = (char *)&reg_getopm_dbg_rx;
			spi_plen = sizeof(reg_getopm_dbg_rx);
		}
		break;
	case CMD_SETLS_DBG:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_SETLS_DBG;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		} else {
			spi_active_cmd = CMD_SETLS_DBG;
			/*
			TODO OFFSET_LEN缺陷，要保证OFFSET_LEN的大小小于或等于
			sizeof(reg_setls_dbg_tx)
			*/
			memcpy(&reg_setls_dbg_tx, PTR_TXVAL(rx), OFFSET_LEN(rx));

			reg_ack[0] = CTX_F_SUCCESS;
			reg_ack[1] = CMD_SETLS_DBG;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		}
		break;
	case CMD_GETLS_DBG:
		if (spi_active_cmd != CMD_UNDEFINE) {
			reg_ack[0] = CTX_F_BUSY;
			reg_ack[1] = CMD_GETLS_DBG;
			spi_ptx = (char *)&reg_ack;
			spi_plen = sizeof(reg_ack);
		} else {
			spi_active_cmd = CMD_GETLS_DBG;
			reg_ack[0] = CTX_F_SUCCESS;
			reg_ack[1] = CMD_GETLS_DBG;
			spi_ptx = (char *)&reg_getls_dbg_rx;
			spi_plen = sizeof(reg_getls_dbg_rx);
		}
		break;
	default:
		reg_ack[0] = CTX_F_ERR;
		spi_ptx = (char *)reg_ack;
		spi_plen = sizeof(reg_ack);
		break;
		// 不能返回-1否则会反复进入中断
	}
	return 0;
}


/**
 * @brief	根据内容填充数据
 * @param	null
 * @retval	null
 * @remarks
 * @see
 */

void spi_fill()
{
}

/*

  spi_dates = T1 + T2

  # 时序
  -----------------------------------------------------------------------------
  | T1 (1)  |   500us (2)  | T2 (3) |   500us (4)  | Xms (5) | R1 (6) | R2 (7)
  -----------------------------------------------------------------------------

  - (1)(3) : 从机在中断或DMA里接收数据，整个过程“迅速”、没有外部中断干扰，
    即使有也在很低的概率才可能发生，本过程可能干扰该过程的只有定时器中断
    给 jiffies 计数
  - (2) : 从机接收“完”T1后得出否存在T2数据，有则继续接收。
  	此过程主机必须等待，保证从机有足够的执行时间，改期间主机发送任何数据将丢失
  - (4) : 从机处理主机的具体命令
  - (5) : 某些命令从机不能立即响应（通常是因为存在R2），需等待，改等待时间ms级别
    （X = 0 ~ 10ms）
  - (6)(7) : 从机返回的具体内容

*/
char spi_dates[100] = {0};
// char spi_dates[500] = {0};
int spi_index = 0;
char spi_tx[] = {
	0x47, 0x4c, 0x49, 0x4e, 0x4b, 0x00, 0x1c, 0x30, 0x00, 0xa0, 0xaa, 0x00
};
char *spi_ptx = spi_tx;
unsigned long spi_isdebug = 0;
unsigned int spi_plen = sizeof(spi_tx);
unsigned int spi_newlen = 4;
unsigned int spi_jiffies = 0;
unsigned int spi_count = 0;
int spi_send = 0;
int arr_index[10] = 0;
int arr_isr[10] = 0;
int arr_cr2[10] = 0;

void EXTI15_10_IRQHandler()
{
	if(EXTI_GetITStatus(EXTI_Line12) != RESET) {
		//按键控制红光输出

		// 下降沿启动SPI
		if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12) == 0) {
			spi_index = 0;
			spi_count = 0;
			spi_newlen = 4;
			// spi_send = 0;
			SPI_OnlyRX();
		}
		/* Clear the EXTI Line 7  */
		EXTI_ClearITPendingBit(EXTI_Line12);
	}
}


void SPI2_IRQHandler(void)
{
	// 接收数据
	// printf("SPI_IRQ %d\n",RxIdx);
	// SPI2_Buffer_Rx[RxIdx++] = SPI_I2S_ReceiveData(SPI2);
	char date;
	int i = 2000;
	static char k = 0;
	unsigned int task_spi = jiffies + 120;
	int ret = 0;

	// while(1) {
	// 	if (time_after(jiffies, task_spi)) {
	// 		break;
	// 	}
	// 	while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) != RESET);
	// 	spi_dates[spi_index] = SPI_I2S_ReceiveData(SPI2);
	// 	spi_index++;
	// 	if (spi_index > 90) {
	// 		spi_index = 0;
	// 	}
	// }
	// return;


	// while (SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) != RESET);

	// while(1) {
	// if (SPI2->SR & 0x08) {
	// 	return;
	// }
	arr_index[spi_count] = spi_index;
	arr_isr[spi_count] = SPI2->SR;
	arr_cr2[spi_count] = SPI2->CR2;
	spi_count++;

	if (SPI_I2S_GetITStatus(SPI2, SPI_I2S_IT_RXNE) != RESET) {
		SPI_I2S_ClearITPendingBit(SPI2, SPI_I2S_IT_RXNE);

#if 1  // 1次中断全部接收
		for (i = 0; i < spi_newlen; i++) {
			while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET) {
				if (time_after(jiffies, task_spi)) {
					goto _RxTimeout;
				}
			}
			spi_dates[spi_index] = SPI_I2S_ReceiveData(SPI2);
			spi_index++;
		}

_RxTimeout:
		ret = spi_analyse(spi_dates, &spi_index);
		switch(ret) {
		case -1:
			SPI_I2S_ClearITPendingBit(SPI2 , SPI_I2S_IT_RXNE);
			SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
			return;
		case -2:
			// printf("spi_newlen %d\r\n", spi_newlen);
			SPI_I2S_ClearITPendingBit(SPI2, SPI_I2S_IT_RXNE);
			SPI_I2S_ITConfig(SPI2, SPI_I2S_IT_RXNE, ENABLE);
			SPI_Off();
			return;
		}

		SPI_OnlyTX();

		task_spi = jiffies + 10;
		for (i = 0; i < spi_plen; i++) {
			spi_send == 1;

			while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) {
				if (time_after(jiffies, task_spi)) {
					goto _TxTimeout;
				}
			}
			SPI_I2S_SendData(SPI2, *(spi_ptx + i));
		}
		while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) {
			if (time_after(jiffies, task_spi)) {
				goto _TxTimeout;
			}
		}
		for (i = 0; i < 10; i++) {}
_TxTimeout:
		SPI_Off();
		// SPI_OnlyRX();

		SPI_I2S_ClearITPendingBit(SPI2 , SPI_I2S_IT_RXNE);
#endif
	}
}
